import { defaultErrorHandler } from '@/unit/error-handler';
import { errorMsg, success, warning } from '@/unit/message';
import { SendOption } from '@/unit/socket';
import { getTokenWithAuth } from '@/unit/tokens';
import Taro, { SocketTask } from '@tarojs/taro';
import {
  action,
  computed,
  makeObservable,
  observable,
} from 'mobx';
import { singleton } from 'tsyringe';
import { MessageType } from './types';

@singleton()
export class Socket {
  @observable public wssUrl =
    'ws://82.156.217.14:4001/socket.io/?EIO=3&transport=websocket';

  @observable public weappUrl =
    'wss://www.liuzhiwei.xyz:4001/socket.io/?EIO=3&transport=websocket';

  @observable public socket: SocketTask | undefined;

  @observable public result: string = '';

  @observable public number: number = 0;

  @observable public heartbeatTimer: number = -1;

  @observable public heartBeatTimeout: number = -1;

  @observable public sid: string = '';

  @observable public message: MessageType =
    new MessageType();

  /**
   * 初始化
   */
  @action public init = async () => {
    try {
      let url: string;
      switch (Taro.getEnv()) {
        case 'WEB':
          url = this.wssUrl;
          break;
        default:
          url = this.weappUrl;
          break;
      }
      const result = await Taro.connectSocket({
        url: url,
        header: {
          'content-type': 'application/json',
          Authorization: getTokenWithAuth(),
        },
      });

      this.socket = result;

      this.socket.onOpen(() => {
        success('socket连接成功');

        // 心跳
        if (this.heartbeatTimer !== -1) {
          clearInterval(this.heartbeatTimer);
          this.heartbeatTimer = -1;
        }

        this.heartbeatTimer = setInterval(() => {
          if (this.heartBeatTimeout !== -1) {
            clearTimeout(this.heartBeatTimeout);
            this.heartBeatTimeout = -1;
          }
          this.heartBeatTimeout = setTimeout(() => {
            console.log('心跳超时');
            this.restart();
          }, 20000) as unknown as number;
          // 心跳保活
          this.sendMessage('heartBeat', 'ping');
        }, 5000) as unknown as number;
      });

      this.socket.onClose(() => {
        warning('socket连接断开正在重连中');
        this.restart();
      });

      this.socket.onError((err) => {
        errorMsg(err.errMsg);
        this.restart();
      });

      this.socket.onMessage((response) => {
        if ((response.data as string).startsWith('0')) {
          const sids = (response.data as string).replace(
            '0',
            ''
          );
          this.sid = (
            JSON.parse(sids) as { sid: string }
          ).sid;
        }
        if ((response.data as string).startsWith('42')) {
          const res = response.data as string;
          let json: string[] = [];

          let start = res.indexOf('['); // 第一次出现的位置
          const start1 = res.indexOf('{');

          if (start < 0) {
            start = start1;
          }
          if (start >= 0 && start1 >= 0) {
            start = Math.min(start, start1);
          }

          if (start >= 0) {
            json = JSON.parse(
              res.substr(start)
            ) as string[]; //截取
          }

          if (
            json[0] === 'heartBeat' &&
            json[1] === 'pong'
          ) {
            if (this.heartBeatTimeout !== -1) {
              clearTimeout(this.heartBeatTimeout);
              this.heartBeatTimeout = -1;
            }
            return;
          } else {
            this.message = new MessageType(
              json[0],
              json[1]
            );
          }
        }
      });

      return result;
    } catch (error) {
      console.log(error);
      defaultErrorHandler(error);
    }
  };

  @action public restart = async () => {
    try {
      clearInterval(this.heartbeatTimer);
      this.heartbeatTimer = -1;
      clearTimeout(this.heartBeatTimeout);
      this.heartBeatTimeout = -1;

      this.socket = await this.init();
      // 断开重连
      // NavigateTo('home');
    } catch (error) {
      defaultErrorHandler(error);
    }
  };

  /**
   * 发送
   * @param data
   * @returns
   */
  @action public sendMessage(event: string, data: any) {
    try {
      if (this.socket?.readyState !== 1) {
        warning('socket链接还未准备好');
        return;
      }
      const options: SendOption = {
        data: `42["${event}",${JSON.stringify(data)}]`,
        success: () => {},
      };
      this.socket.send(options);
    } catch (error) {
      defaultErrorHandler(error);
    }
  }

  /**
   * 监听消息
   * @param type
   * @param callback
   * @returns
   */
  @action public listenerType = async (
    // type: string,
    callback: Function
  ) => {
    try {
      if (!this.socket?.OPEN || !this.socket) return;
      this.socket.onMessage((response) => {
        const res = response.data as string;
        if (res.startsWith('42')) {
          let json: string[] = [];

          let start = res.indexOf('['); // 第一次出现的位置
          const start1 = res.indexOf('{');

          if (start < 0) {
            start = start1;
          }
          if (start >= 0 && start1 >= 0) {
            start = Math.min(start, start1);
          }

          if (start >= 0) {
            json = JSON.parse(
              res.substr(start)
            ) as string[]; //截取
          }
          callback(json[0], json[1]);
        }
      });
    } catch (error) {
      defaultErrorHandler(error);
    }
  };

  // @action public onMessageEvent = (response: string) => {
  //   try {
  //     let res: Array<string | unknown> = [];
  //     console.log('new');
  //     if (!response.startsWith('42')) return;
  //     let start = response.indexOf('['); // 第一次出现的位置
  //     const start1 = response.indexOf('{');

  //     if (start < 0) {
  //       start = start1;
  //     }
  //     if (start >= 0 && start1 >= 0) {
  //       start = Math.min(start, start1);
  //     }

  //     if (start >= 0) {
  //       res = JSON.parse(
  //         response.substr(start)
  //       ) as string[]; //截取
  //     }
  //     console.log('res', res);
  //     document.dispatchEvent(
  //       new CustomEvent(
  //         res[0] as string,
  //         res[1] as CustomEventInit<unknown> | undefined
  //       )
  //     );
  //   } catch (error) {
  //     defaultErrorHandler(error);
  //   }
  // };

  // /**
  //  * 监听指定类型 返回消息不做处理
  //  * @param number
  //  * @param callback
  //  * @returns
  //  */
  // @action public socketStartWith = (
  //   number: number,
  //   callback: Function
  // ) => {
  //   try {
  //     if (!this.socket?.OPEN || !this.socket) return;
  //     this.socket.onMessage((response) => {
  //       if (
  //         (response.data as string).startsWith(
  //           String(number)
  //         )
  //       ) {
  //         callback(response.data);
  //       }
  //     });
  //   } catch (error) {
  //     defaultErrorHandler(error);
  //   }
  // };

  @computed get getResult() {
    return this.result;
  }

  constructor() {
    makeObservable(this);
  }
}
